home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / comm / amigatcp.3 < prev    next >
Text File  |  1989-03-18  |  43KB  |  1,827 lines

  1. Path: xanth!ukma!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i082:  amigatcp - tcp/ip for the amiga, Part03/06
  5. Message-ID: <12330@swan.ulowell.edu>
  6. Date: 17 Mar 89 23:17:43 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1816
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: rminnich@super.org (Ronald G. Minnich)
  12. Posting-number: Volume 89, Issue 82
  13. Archive-name: comm/amigatcp.3
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    ftpserv.c
  23. #    tcpsubr.c
  24. #    ip.c
  25. #    udp.c
  26. # This archive created: Fri Mar 17 17:57:41 1989
  27. cat << \SHAR_EOF > ftpserv.c
  28. /* FTP Server state machine - see RFC 959 */
  29.  
  30. #define    LINELEN        128    /* Length of command buffer */
  31.  
  32. #include <stdio.h>
  33. #include "machdep.h"
  34. #include "mbuf.h"
  35. #include "netuser.h"
  36. #include "timer.h"
  37. #include "tcp.h"
  38. #include "ftp.h"
  39.  
  40. /* Command table */
  41. static char *commands[] = {
  42.     "user",
  43. #define    USER_CMD    0
  44.     "acct",
  45. #define    ACCT_CMD    1
  46.     "pass",
  47. #define    PASS_CMD    2
  48.     "type",
  49. #define    TYPE_CMD    3
  50.     "list",
  51. #define    LIST_CMD    4
  52.     "cwd",
  53. #define    CWD_CMD        5
  54.     "dele",
  55. #define    DELE_CMD    6
  56.     "name",
  57. #define    NAME_CMD    7
  58.     "quit",
  59. #define    QUIT_CMD    8
  60.     "retr",
  61. #define    RETR_CMD    9
  62.     "stor",
  63. #define    STOR_CMD    10
  64.     "port",
  65. #define    PORT_CMD    11
  66.     "nlst",
  67. #define    NLST_CMD    12
  68.     "pwd",
  69. #define    PWD_CMD        13
  70.     "xpwd",            /* For compatibility with 4.2BSD */
  71. #define    XPWD_CMD    14
  72.     NULLCHAR
  73. };
  74.  
  75. /* Response messages */
  76. static char banner[] = "220 %s FTP Ready\r\n";
  77. static char badcmd[] = "500 Unknown command\r\n";
  78. static char nopass[] = "202 Password not needed\r\n";
  79. static char logged[] = "230 Logged in\r\n";
  80. static char typeok[] = "200 Type OK\r\n";
  81. static char cwdok[] = "250 CWD OK\r\n";
  82. static char pwdmsg[] = "257 \"%s\" is current directory\r\n";
  83. static char badtype[] = "501 Unknown type\r\n";
  84. static char badport[] = "501 Bad port syntax\r\n";
  85. static char unimp[] = "502 Command not yet implemented\r\n";
  86. static char bye[] = "221 Goodbye!\r\n";
  87. static char nodir[] = "553 Can't read directory\r\n";
  88. static char cantopen[] = "550 Can't open file\r\n";
  89. static char sending[] = "150 Opening data connection for %s %s\r\n";
  90. static char cantmake[] = "553 Can't create file\r\n";
  91. static char portok[] = "200 Port command okay\r\n";
  92. static char rxok[] = "226 File received OK\r\n";
  93. static char txok[] = "226 File sent OK\r\n";
  94.  
  95. static struct tcb *ftp_tcb;
  96.  
  97. /* Start up FTP service */
  98. ftp_start(argc,argv)
  99. int argc;
  100. char *argv[];
  101. {
  102.     struct socket lsocket;
  103.     void r_ftp(),s_ftp();
  104.  
  105.     lsocket.address = ip_addr;
  106.     if(argc < 2)
  107.         lsocket.port = FTP_PORT;
  108.     else
  109.         lsocket.port = atoi(argv[1]);
  110.  
  111.     ftp_tcb = open_tcp(&lsocket,NULLSOCK,TCP_PASSIVE,0,r_ftp,NULLVFP,s_ftp,0,(int *)NULL);
  112. }
  113. ftp_stop()
  114. {
  115.     if(ftp_tcb != NULLTCB)
  116.         close_tcp(ftp_tcb);
  117. }
  118. /* FTP server control channel connection state change upcall handler */
  119. static
  120. void
  121. s_ftp(tcb,old,new)
  122. struct tcb *tcb;
  123. char old,new;
  124. {
  125.     extern char hostname[];
  126.     struct ftp *ftp,*ftp_create();
  127.     void ftp_delete();
  128.     char *inet_ntoa(),*pwd();
  129.  
  130.     switch(new){
  131. #ifdef    QUICKSTART
  132.     case SYN_RECEIVED:
  133. #else
  134.     case ESTABLISHED:
  135. #endif
  136.         if((ftp = ftp_create(LINELEN)) == NULLFTP){
  137.             /* No space, kill connection */
  138.             close_tcp(tcb);
  139.             return;
  140.         }
  141.         ftp->control = tcb;    /* Downward link */
  142.         tcb->user = (int *)ftp;    /* Upward link */
  143.  
  144.         /* Set default data port */
  145.         ftp->port.address = tcb->conn.remote.address;
  146.         ftp->port.port = FTPD_PORT;
  147.  
  148.         /* Note current directory */
  149. #ifndef    AMIGA
  150.         ftp->cd = pwd();
  151. #endif
  152.         log(tcb,"open FTP");
  153.         tprintf(ftp->control,banner,hostname);
  154.         break;        
  155.     case CLOSE_WAIT:
  156.         close_tcp(tcb);
  157.         break;
  158.     case CLOSED:
  159.         log(tcb,"close FTP");
  160.         if((ftp = (struct ftp *)tcb->user) != NULLFTP)
  161.             ftp_delete(ftp);
  162.         /* Check if server is being shut down */
  163.         if(tcb == ftp_tcb)
  164.             ftp_tcb = NULLTCB;
  165.         del_tcp(tcb);
  166.         break;
  167.     }
  168. }
  169.  
  170. /* FTP control channel receiver upcall handler */
  171. static
  172. void
  173. r_ftp(tcb,cnt)
  174. struct tcb *tcb;
  175. int16 cnt;
  176. {
  177.     register struct ftp *ftp;
  178.     char *index(),c;
  179.     struct mbuf *bp;
  180.     void docommand();
  181.  
  182.     if((ftp = (struct ftp *)tcb->user) == NULLFTP){
  183.         /* Unknown connection, just kill it */
  184.         close_tcp(tcb);
  185.         return;
  186.     }
  187.     switch(ftp->state){
  188.     case COMMAND_STATE:
  189.         /* Assemble an input line in the session buffer. Return if incomplete */
  190.         recv_tcp(tcb,&bp,0);
  191.         while(pullup(&bp,&c,1) == 1){
  192.             switch(c){
  193.             case '\r':    /* Strip cr's */
  194.                 continue;
  195.             case '\n':    /* Complete line; process it */
  196.                 ftp->buf[ftp->cnt] = '\0';
  197.                 docommand(ftp);
  198.                 ftp->cnt = 0;
  199.                 break;
  200.             default:    /* Assemble line */
  201.                 if(ftp->cnt != LINELEN-1)
  202.                     ftp->buf[ftp->cnt++] = c;
  203.                 break;
  204.             }
  205.         }
  206.         /* else no linefeed present yet to terminate command */
  207.         break;
  208.     case SENDING_STATE:
  209.     case RECEIVING_STATE:
  210.         /* Leave commands pending on receive queue until
  211.          * present command is done
  212.          */
  213.         break;
  214.     }
  215. }
  216.  
  217. /* FTP server data channel connection state change upcall handler */
  218. void
  219. s_ftpd(tcb,old,new)
  220. struct tcb *tcb;
  221. char old,new;
  222. {
  223.     struct ftp *ftp;
  224. #ifndef    CPM
  225. #ifndef    AMIGA
  226.     char *cdsave;
  227. #endif
  228. #endif
  229.  
  230.     if((ftp = (struct ftp *)tcb->user) == NULLFTP){
  231.         /* Unknown connection, kill it */
  232.         close_tcp(tcb);
  233.         return;
  234.     }
  235.     switch(new){
  236.     case FINWAIT2:
  237.     case TIME_WAIT:
  238.         if(ftp != NULLFTP && ftp->state == SENDING_STATE){
  239.             /* We've received an ack of our FIN, so
  240.              * send a completion message on the control channel
  241.              */
  242.             ftp->state = COMMAND_STATE;
  243.             tprintf(ftp->control,txok);
  244.             /* Kick command parser if something is waiting */
  245.             if(ftp->control->rcvcnt != 0)
  246.                 r_ftp(ftp->control,ftp->control->rcvcnt);
  247.         }
  248.         break;        
  249.     case CLOSE_WAIT:
  250.         close_tcp(tcb);
  251.         if(ftp != NULLFTP && ftp->state == RECEIVING_STATE){
  252.             /* End of file received on incoming file */
  253. #ifdef    CPM
  254.             if(ftp->type == ASCII_TYPE)
  255.                 putc(CTLZ,ftp->fp);
  256. #endif
  257. #ifndef    CPM
  258. #ifndef    AMIGA
  259.             cdsave = pwd();        /* Save current directory */
  260.             chdir(ftp->cd);        /* Switch to user's directory*/
  261. #endif
  262. #endif
  263.             fclose(ftp->fp);
  264. #ifndef    CPM
  265. #ifndef    AMIGA
  266.             if(cdsave != NULLCHAR){
  267.                 chdir(cdsave);        /* And back */
  268.                 free(cdsave);
  269.             }
  270. #endif
  271. #endif
  272.             ftp->fp = NULLFILE;
  273.             ftp->state = COMMAND_STATE;
  274.             tprintf(ftp->control,rxok);
  275.             /* Kick command parser if something is waiting */
  276.             if(ftp->control->rcvcnt != 0)
  277.                 r_ftp(ftp->control,ftp->control->rcvcnt);
  278.         }
  279.         break;
  280.     case CLOSED:
  281.         if(ftp != NULLFTP)
  282.             ftp->data = NULLTCB;
  283.         del_tcp(tcb);
  284.         break;
  285.     }
  286. }
  287.  
  288. /* Parse and execute ftp commands */
  289. static
  290. void
  291. docommand(ftp)
  292. register struct ftp *ftp;
  293. {
  294.     void r_ftpd(),t_ftpd(),s_ftpd();
  295.     char *cmd,*arg,*cp,**cmdp;
  296.     char *index(),*malloc(),*strcpy();
  297.     struct socket dport;
  298. #ifndef    CPM
  299. #ifndef    AMIGA
  300.     FILE *dir();
  301.     char *cdsave;
  302. #endif
  303. #endif
  304.  
  305.     cmd = ftp->buf;
  306.     if(ftp->cnt == 0){
  307.         /* Can't be a legal FTP command */
  308.         tprintf(ftp->control,badcmd);
  309.         return;
  310.     }    
  311.     cmd = ftp->buf;
  312.  
  313.     /* Translate entire buffer to lower case */
  314.     for(cp = cmd;*cp != '\0';cp++)
  315.         *cp = tolower(*cp);
  316.  
  317.     /* Find command in table; if not present, return syntax error */
  318.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  319.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  320.             break;
  321.     if(*cmdp == NULLCHAR){
  322.         tprintf(ftp->control,badcmd);
  323.         return;
  324.     }
  325.     arg = &cmd[strlen(*cmdp)];
  326.     while(*arg == ' ')
  327.         arg++;
  328.     /* Execute specific command */
  329.     switch(cmdp-commands){
  330.     case USER_CMD:
  331.         if((ftp->username = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  332.             close_tcp(ftp->control);
  333.             break;
  334.         }
  335.         strcpy(ftp->username,arg);
  336.         tprintf(ftp->control,logged);
  337.         break;
  338.     case TYPE_CMD:
  339.         switch(*arg){
  340.         case 'a':    /* Ascii */
  341.             ftp->type = ASCII_TYPE;
  342.             tprintf(ftp->control,typeok);
  343.             break;
  344.         case 'b':    /* Binary */
  345.         case 'i':    /* Image */
  346.             ftp->type = IMAGE_TYPE;
  347.             tprintf(ftp->control,typeok);
  348.             break;
  349.         default:    /* Invalid */
  350.             tprintf(ftp->control,badtype);
  351.             break;
  352.         }
  353.         break;
  354.     case QUIT_CMD:
  355.         tprintf(ftp->control,bye);
  356.         close_tcp(ftp->control);
  357.         break;
  358.     case RETR_CMD:
  359.         /* Disk operation; return ACK now */
  360.         tcp_output(ftp->control);
  361. #ifndef    CPM
  362. #ifndef    AMIGA
  363.         cdsave = pwd();        /* Save current directory */
  364.         chdir(ftp->cd);        /* Switch to user's directory*/
  365. #endif
  366. #endif
  367.         ftp->fp = fopen(arg,"r");
  368. #ifndef    CPM
  369. #ifndef    AMIGA
  370.         chdir(cdsave);        /* And back */
  371.         free(cdsave);
  372. #endif
  373. #endif
  374.         if(ftp->fp == NULLFILE){
  375.             tprintf(ftp->control,cantopen);
  376.         } else {
  377.             log(ftp->control,"RETR %s/%s",ftp->cd,arg);
  378.             dport.address = ip_addr;
  379.             dport.port = FTPD_PORT;
  380.             ftp->state = SENDING_STATE;
  381.             tprintf(ftp->control,sending,"RETR",arg);
  382.  
  383.             /* This hack is just so we can talk to ourselves */
  384.             ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
  385.              0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
  386.  
  387.             ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
  388.              0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
  389.         }
  390.         break;
  391.     case STOR_CMD:
  392.         /* Disk operation; return ACK now */
  393.         tcp_output(ftp->control);
  394. #ifndef    CPM
  395. #ifndef    AMIGA
  396.         cdsave = pwd();        /* Save current directory */
  397.         chdir(ftp->cd);        /* Switch to user's directory */
  398. #endif
  399. #endif    
  400.         ftp->fp = fopen(arg,"w");
  401. #ifndef    CPM
  402. #ifndef    AMIGA
  403.         chdir(cdsave);            /* And back */
  404.         free(cdsave);
  405. #endif
  406. #endif        
  407.         if(ftp->fp == NULLFILE){
  408.             tprintf(ftp->control,cantmake);
  409.         } else {
  410.             log(ftp->control,"STOR %s/%s",ftp->cd,arg);
  411.             dport.address = ip_addr;
  412.             dport.port = FTPD_PORT;
  413.             ftp->state = RECEIVING_STATE;
  414.             tprintf(ftp->control,sending,"STOR",arg);
  415.  
  416.             /* This hack is just so we can talk to ourselves */
  417.             ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
  418.              0,r_ftpd,NULLVFP,s_ftpd,ftp->control->tos,(int *)ftp);
  419.  
  420.             ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
  421.              0,r_ftpd,NULLVFP,s_ftpd,ftp->control->tos,(int *)ftp);
  422.         }
  423.         break;
  424.     case PORT_CMD:
  425.         if(pport(&ftp->port,arg) == -1){
  426.             tprintf(ftp->control,badport);
  427.         } else {
  428.             tprintf(ftp->control,portok);
  429.         }
  430.         break;
  431. /* #ifndef CPM */
  432. #ifndef    AMIGA
  433.     case LIST_CMD:
  434.         /* Disk operation; return ACK now */
  435.         tcp_output(ftp->control);
  436.  
  437.         cdsave = pwd();        /* Save current directory */
  438.         chdir(ftp->cd);        /* Switch to user's directory */
  439.         ftp->fp = dir(arg,1);
  440.         chdir(cdsave);        /* And back */
  441.         free(cdsave);
  442.  
  443.         if(ftp->fp == NULLFILE){
  444.             tprintf(ftp->control,nodir);
  445.             break;
  446.         }            
  447.         dport.address = ip_addr;
  448.         dport.port = FTPD_PORT;
  449.         ftp->state = SENDING_STATE;
  450.         tprintf(ftp->control,sending,"LIST",arg);
  451.  
  452.         /* This hack is just so we can talk to ourselves */
  453.         ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
  454.          0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
  455.  
  456.         ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
  457.          0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
  458.         break;
  459.     case NLST_CMD:
  460.         /* Disk operation; return ACK now */
  461.         tcp_output(ftp->control);
  462.  
  463.         cdsave = pwd();        /* Save current directory */
  464.         chdir(ftp->cd);        /* Switch to user's directory */
  465.         ftp->fp = dir(arg,0);
  466.         chdir(cdsave);        /* And back */
  467.         free(cdsave);
  468.  
  469.         if(ftp->fp == NULLFILE){
  470.             tprintf(ftp->control,nodir);
  471.             break;
  472.         }            
  473.         dport.address = ip_addr;
  474.         dport.port = FTPD_PORT;
  475.         ftp->state = SENDING_STATE;
  476.         tprintf(ftp->control,sending,"NLST",arg);
  477.  
  478.         /* This hack is just so we can talk to ourselves */
  479.         ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
  480.          0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
  481.  
  482.         ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
  483.          0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
  484.         break;
  485.     case CWD_CMD:
  486.         tcp_output(ftp->control);    /* Disk operation; return ACK now */
  487.  
  488.         cdsave = pwd();        /* Save current directory */
  489.         chdir(ftp->cd);        /* Go to user's context */
  490.         if(chdir(arg) == 0){    /* Attempt switch */
  491.             /* Succeeded, record in control block */
  492.             free(ftp->cd);
  493.             ftp->cd = pwd();
  494.             tprintf(ftp->control,cwdok);
  495.         } else {
  496.             /* Failed, don't change anything */
  497.             tprintf(ftp->control,nodir);
  498.         }
  499.         chdir(cdsave);            /* Go back */
  500.         free(cdsave);
  501.         break;
  502.     case XPWD_CMD:
  503.     case PWD_CMD:
  504.         tprintf(ftp->control,pwdmsg,ftp->cd);
  505.         break;
  506. #else
  507.     case LIST_CMD:
  508.     case NLST_CMD:
  509.     case CWD_CMD:
  510.     case XPWD_CMD:
  511.     case PWD_CMD:
  512. #endif
  513.     case ACCT_CMD:        
  514.     case DELE_CMD:
  515.         tprintf(ftp->control,unimp);
  516.         break;
  517.     case PASS_CMD:
  518.         tprintf(ftp->control,nopass);
  519.         break;
  520.     }
  521. }
  522. static
  523. int
  524. pport(sock,arg)
  525. struct socket *sock;
  526. char *arg;
  527. {
  528.     int32 n;
  529.     int atoi(),i;
  530.  
  531.     n = 0;
  532.     for(i=0;i<4;i++){
  533.         n = atoi(arg) + (n << 8);
  534.         if((arg = index(arg,',')) == NULLCHAR)
  535.             return -1;
  536.         arg++;
  537.     }
  538.     sock->address = n;
  539.     n = atoi(arg);
  540.     if((arg = index(arg,',')) == NULLCHAR)
  541.         return -1;
  542.     arg++;
  543.     n = atoi(arg) + (n << 8);
  544.     sock->port = n;
  545.     return 0;
  546. }
  547. SHAR_EOF
  548. cat << \SHAR_EOF > tcpsubr.c
  549. #ifdef    TRACE
  550. #include <stdio.h>
  551. #endif
  552.  
  553. #include "machdep.h"
  554. #include "timer.h"
  555. #include "mbuf.h"
  556. #include "netuser.h"
  557. #include "internet.h"
  558. #include "tcp.h"
  559.  
  560. struct tcb *tcbs[NTCB];
  561.  
  562. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  563. struct tcb *
  564. lookup_tcb(conn)
  565. struct connection *conn;
  566. {
  567.     register struct tcb *tcb;
  568.     int16 hash_tcb();    
  569.  
  570.     tcb = tcbs[hash_tcb(conn)];
  571.     while(tcb != NULLTCB){
  572.         /* Yet another structure compatibility hack */
  573.         if(conn->local.address == tcb->conn.local.address
  574.          && conn->remote.address == tcb->conn.remote.address
  575.          && conn->local.port == tcb->conn.local.port
  576.          && conn->remote.port == tcb->conn.remote.port)
  577.             break;
  578.         tcb = tcb->next;
  579.     }
  580.     return tcb;
  581. }
  582.  
  583. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  584. struct tcb *
  585. create_tcb(conn)
  586. struct connection *conn;
  587. {
  588.     char *calloc();
  589.     register struct tcb *tcb;
  590.     void tcp_timeout(),tcp_msl();
  591.     void link_tcb();
  592.  
  593.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  594.         return tcb;
  595.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  596.         return NULLTCB;
  597.     bcopy((char *)conn,(char *)&tcb->conn,sizeof(struct connection));
  598.  
  599.     tcb->mss = DEF_MSS;
  600.     tcb->srtt = DEF_RTT * MSPTICK;
  601.     /* Initialize retransmission timeout */
  602.     tcb->timer.start = (BETA * tcb->srtt)/MSPTICK;
  603.  
  604.     tcb->timer.func = tcp_timeout;
  605.     tcb->timer.arg = (int *)tcb;
  606.  
  607.     link_tcb(tcb);
  608.     return tcb;
  609. }
  610.  
  611. /* Close our TCB */
  612. void
  613. close_self(tcb,reason)
  614. register struct tcb *tcb;
  615. char reason;
  616. {
  617.     struct reseq *rp,*rp1;
  618.  
  619.     stop_timer(&tcb->timer);
  620.     tcb->reason = reason;
  621.  
  622.     /* Flush reassembly queue; nothing more can arrive */
  623.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  624.         rp1 = rp->next;
  625.         free_p(rp->bp);
  626.         free((char *)rp);
  627.     }
  628.     tcb->reseq = NULLRESEQ;
  629.     setstate(tcb,CLOSED);
  630. }
  631.  
  632. /* Determine initial sequence number */
  633.  
  634. #ifdef    AMIGA
  635. /*
  636.  *  routine called at startup time with inital value of iss for system.  This
  637.  *  is probably based on the time or something
  638.  */
  639. static int32 seq;
  640.  
  641. void
  642. setiss(initval)
  643.     int32 initval;
  644. {
  645.     seq = initval;
  646. }
  647. #endif
  648.  
  649. int32
  650. iss()
  651. {
  652. #ifndef    AMIGA
  653.     static int32 seq;
  654. #endif
  655.     seq += 250000;
  656.     return seq;
  657. }
  658.  
  659. /* Sequence number comparisons
  660.  * Return true if x is between low and high inclusive,
  661.  * false otherwise
  662.  */
  663. int
  664. seq_within(x,low,high)
  665. register int32 x,low,high;
  666. {
  667.     if(low <= high){
  668.         if(low <= x && x <= high)
  669.             return 1;
  670.     } else {
  671.         if(low >= x && x >= high)
  672.             return 1;
  673.     }
  674.     return 0;
  675. }
  676. int
  677. seq_lt(x,y)
  678. register int32 x,y;
  679. {
  680.     return (long)(x-y) < 0;
  681. }
  682. int
  683. seq_le(x,y)
  684. register int32 x,y;
  685. {
  686.     return (long)(x-y) <= 0;
  687. }
  688. int
  689. seq_gt(x,y)
  690. register int32 x,y;
  691. {
  692.     return (long)(x-y) > 0;
  693. }
  694. int
  695. seq_ge(x,y)
  696. register int32 x,y;
  697. {
  698.     return (long)(x-y) >= 0;
  699. }
  700.  
  701. /* Hash a connect structure into the hash chain header array */
  702. static int16
  703. hash_tcb(conn)
  704. struct connection *conn;
  705. {
  706.     register int16 hval;
  707.  
  708.     /* Compute hash function on connection structure */
  709.     hval = hiword(conn->remote.address);
  710.     hval ^= loword(conn->remote.address);
  711.     hval ^= hiword(conn->local.address);
  712.     hval ^= loword(conn->local.address);
  713.     hval ^= conn->remote.port;
  714.     hval ^= conn->local.port;
  715.     hval %= NTCB;
  716.     return hval;
  717. }
  718. /* Insert TCB at head of proper hash chain */
  719. void
  720. link_tcb(tcb)
  721. register struct tcb *tcb;
  722. {
  723.     register struct tcb **tcbhead;
  724.     int16 hash_tcb();
  725.     char i_state;
  726.  
  727.     tcb->prev = NULLTCB;
  728.     i_state = disable();
  729.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  730.     tcb->next = *tcbhead;
  731.     if(tcb->next != NULLTCB){
  732.         tcb->next->prev = tcb;
  733.     }
  734.     *tcbhead = tcb;
  735.     restore(i_state);
  736. }
  737. /* Remove TCB from whatever hash chain it may be on */
  738. void
  739. unlink_tcb(tcb)
  740. register struct tcb *tcb;
  741. {
  742.     register struct tcb **tcbhead;
  743.     int16 hash_tcb();
  744.     char i_state;
  745.  
  746.     i_state = disable();
  747.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  748.     if(*tcbhead == tcb)
  749.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  750.     if(tcb->prev != NULLTCB)
  751.         tcb->prev->next = tcb->next;
  752.     if(tcb->next != NULLTCB)
  753.         tcb->next->prev = tcb->prev;
  754.     restore(i_state);
  755. }
  756. void
  757. setstate(tcb,newstate)
  758. register struct tcb *tcb;
  759. register char newstate;
  760. {
  761.     register char oldstate;
  762.  
  763.     oldstate = tcb->state;
  764.     tcb->state = newstate;
  765.     if(tcb->s_upcall){
  766.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  767.     }
  768.     /* Notify the user that he can begin sending data */
  769.     if(tcb->t_upcall && newstate == ESTABLISHED){
  770.         (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  771.     }
  772. }
  773. #ifdef    TRACE
  774. /* TCP connection states */
  775. char *tcpstates[] = {
  776.     "Closed",
  777.     "Listen",
  778.     "SYN sent",
  779.     "SYN received",
  780.     "Established",
  781.     "FIN wait 1",
  782.     "FIN wait 2",
  783.     "Close wait",
  784.     "Closing",
  785.     "Last ACK",
  786.     "Time wait"
  787. };
  788. /* TCP segment header flags */
  789. char *tcpflags[] = {
  790.     "FIN",    /* 0x01 */
  791.     "SYN",    /* 0x02 */
  792.     "RST",    /* 0x04 */
  793.     "PSH",    /* 0x08 */
  794.     "ACK",    /* 0x10 */
  795.     "URG"    /* 0x20 */
  796. };
  797.  
  798. /* TCP closing reasons */
  799. char *reasons[] = {
  800.     "Normal",
  801.     "Reset",
  802.     "Timeout",
  803.     "ICMP"
  804. };
  805. /* Return 1 if arg is a valid TCB, 0 otherwise */
  806. int
  807. tcpval(tcb)
  808. struct tcb *tcb;
  809. {
  810.     register int i;
  811.     register struct tcb *tcb1;
  812.  
  813.     for(i=0;i<NTCB;i++){
  814.         for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  815.             if(tcb1 == tcb)
  816.                 return 1;
  817.         }
  818.     }
  819.     return 0;
  820. }
  821.  
  822. /* Dump TCP stats and summary of all TCBs
  823. /* &TCB Rcv-Q Snd-Q  Local socket           Remote socket          State
  824.  * 1234     0     0  xxx.xxx.xxx.xxx:xxxxx  xxx.xxx.xxx.xxx:xxxxx  Established
  825.  */
  826. int
  827. tcpstat()
  828. {
  829.     register int i;
  830.     register struct tcb *tcb;
  831.     char *psocket();
  832.  
  833.     printf("conout %u conin %u reset out %u runt %u chksum err %u bdcsts %u\r\n",
  834.         tcp_stat.conout,tcp_stat.conin,tcp_stat.resets,tcp_stat.runt,
  835.         tcp_stat.checksum,tcp_stat.bdcsts);
  836. #ifdef    AMIGA
  837.     printf("&TCB   Rcv-Q Snd-Q  Local socket           Remote socket          State\r\n");
  838. #else
  839.     printf("&TCB Rcv-Q Snd-Q  Local socket           Remote socket          State\r\n");
  840. #endif
  841.     for(i=0;i<NTCB;i++){
  842.         for(tcb=tcbs[i];tcb != NULLTCB;tcb = tcb->next){
  843. #ifdef    AMIGA
  844.             printf("%6lx%6u%6u  ",(unsigned long)tcb,
  845.                         tcb->rcvcnt,tcb->sndcnt);
  846. #else
  847.             printf("%4x%6u%6u  ",(int)tcb,tcb->rcvcnt,tcb->sndcnt);
  848. #endif
  849.             printf("%-23s",psocket(&tcb->conn.local));
  850.             printf("%-23s",psocket(&tcb->conn.remote));
  851.             printf("%-s\r\n",tcpstates[tcb->state]);
  852.         }
  853.     }
  854.     fflush(stdout);
  855.     return 0;
  856. }
  857. /* Dump a TCP control block */
  858. void
  859. state_tcp(tcb)
  860. struct tcb *tcb;
  861. {
  862.     int32 sent,recvd;
  863.  
  864.     if(tcb == NULLTCB)
  865.         return;
  866.     /* Compute total data sent and received; take out SYN and FIN */
  867.     sent = tcb->snd.una - tcb->iss;    /* Acknowledged data only */
  868.     recvd = tcb->rcv.nxt - tcb->irs;
  869.     switch(tcb->state){
  870.     case LISTEN:
  871.     case SYN_SENT:        /* Nothing received or acked yet */
  872.         sent = recvd = 0;    
  873.         break;
  874.     case SYN_RECEIVED:
  875.         recvd--;    /* Got SYN, no data acked yet */
  876.         sent = 0;
  877.         break;
  878.     case ESTABLISHED:    /* Got and sent SYN */
  879.     case FINWAIT1:        /* FIN not acked yet */
  880.         sent--;
  881.         recvd--;
  882.         break;
  883.     case FINWAIT2:        /* Our SYN and FIN both acked */
  884.         sent -= 2;
  885.         recvd--;
  886.         break;
  887.     case CLOSE_WAIT:    /* Got SYN and FIN, our FIN not yet acked */
  888.     case CLOSING:
  889.     case LAST_ACK:
  890.         sent--;
  891.         recvd -= 2;
  892.         break;
  893.     case TIME_WAIT:        /* Sent and received SYN/FIN, all acked */
  894.         sent -= 2;
  895.         recvd -= 2;
  896.         break;
  897.     }
  898.     printf("Local: %s",psocket(&tcb->conn.local));
  899.     printf(" Remote: %s",psocket(&tcb->conn.remote));
  900.     printf(" State: %s\r\n",tcpstates[tcb->state]);
  901.     printf("      Init seq    Unack     Next      WL1      WL2  Wind   MSS Queue      Total\r\n");
  902.     printf("Send:");
  903.     printf("%9lx",tcb->iss);
  904.     printf("%9lx",tcb->snd.una);
  905.     printf("%9lx",tcb->snd.nxt);
  906.     printf("%9lx",tcb->snd.wl1);
  907.     printf("%9lx",tcb->snd.wl2);
  908.     printf("%6u",tcb->snd.wnd);
  909.     printf("%6u",tcb->mss);
  910.     printf("%6u",tcb->sndcnt);
  911.     printf("%11lu\r\n",sent);
  912.  
  913.     printf("Recv:");
  914.     printf("%9lx",tcb->irs);
  915.     printf("         ");
  916.     printf("%9lx",tcb->rcv.nxt);
  917.     printf("         ");
  918.     printf("         ");
  919.     printf("%6u",tcb->rcv.wnd);
  920.     printf("      ");
  921.     printf("%6u",tcb->rcvcnt);
  922.     printf("%11lu\r\n",recvd);
  923.  
  924.     if(tcb->reseq != (struct reseq *)NULL){
  925.         register struct reseq *rp;
  926.  
  927.         printf("Reassembly queue:\r\n");
  928.         for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
  929.             printf("  seq x%lx %u bytes\r\n",rp->seg.seq,rp->length);
  930.         }
  931.     }
  932.     printf("Retry %u",tcb->retry);
  933.     switch(tcb->timer.state){
  934.     case TIMER_STOP:
  935.         printf(" Timer stopped");
  936.         break;
  937.     case TIMER_RUN:
  938.         printf(" Timer running (%ld/%ld mS)",
  939.          (long)MSPTICK * (tcb->timer.start - tcb->timer.count),
  940.          (long)MSPTICK * tcb->timer.start);
  941.         break;
  942.     case TIMER_EXPIRE:
  943.         printf(" Timer expired");
  944.     }
  945.     printf(" Smoothed round trip time %ld mS\r\n",tcb->srtt);
  946.     fflush(stdout);
  947. }
  948.  
  949. /* Dump a TCP segment header. Assumed to be in network byte order */
  950. void
  951. tcp_dump(bp,source,dest,check)
  952. struct mbuf *bp;
  953. int32 source,dest;    /* IP source and dest addresses */
  954. int check;        /* 0 if checksum test is to be bypassed */
  955. {
  956.     int hdr_len,i;
  957.     register struct tcp_header *tcph;
  958.     struct pseudo_header ph;
  959.     char tmpbuf;
  960.  
  961.     if(bp == NULLBUF)
  962.         return;
  963.     /* If packet isn't in a single buffer, make a temporary copy and
  964.      * note the fact so we free it later
  965.      */
  966.     if(bp->next != NULLBUF){
  967.         bp = copy_p(bp,len_mbuf(bp));
  968.         tmpbuf = 1;
  969.     } else
  970.         tmpbuf = 0;
  971.         
  972.     tcph = (struct tcp_header *)bp->data;
  973.     hdr_len = hinibble(tcph->offset) * sizeof(int32);
  974.     printf("TCP: %u->%u Seq x%lx",
  975.         ntohs(tcph->source),ntohs(tcph->dest),
  976.         ntohl(tcph->seq),ntohl(tcph->ack));
  977.     
  978.     if(tcph->flags & ACK)
  979.         printf(" Ack x%lx",ntohl(tcph->ack));
  980.     for(i=0;i<6;i++){
  981.         if(tcph->flags & 1 << i){
  982.             printf(" %s",tcpflags[i]);
  983.         }
  984.     }
  985.     printf(" Wnd %u",ntohs(tcph->wnd));
  986.     if(tcph->flags & URG)
  987.         printf(" UP x%x",ntohs(tcph->up));
  988.  
  989.     if(hdr_len > sizeof(struct tcp_header)){
  990.         struct mss *mssp;
  991.     
  992.         mssp = (struct mss *)(tcph + 1);
  993.         if(mssp->kind == MSS_KIND && mssp->length == MSS_LENGTH){
  994.             printf(" MSS %u",ntohs(mssp->mss));
  995.         }
  996.     }
  997.     /* Verify checksum */
  998.     if(check){
  999.         ph.source = source;
  1000.         ph.dest = dest;
  1001.         ph.protocol = TCP_PTCL;
  1002.         ph.length = len_mbuf(bp);
  1003.         ph.zero = 0;
  1004.         if((i = cksum(&ph,bp,ph.length)) != 0)
  1005.             printf(" CHECKSUM ERROR (%u)",i);
  1006.     }
  1007.     printf("\r\n");
  1008.     if(tmpbuf)
  1009.         free_p(bp);
  1010. }
  1011. #endif
  1012. SHAR_EOF
  1013. cat << \SHAR_EOF > ip.c
  1014. /* Upper half of IP, consisting of send/receive primitives, including
  1015.  * fragment reassembly, for higher level protocols.
  1016.  * Not needed when running as a standalone gateway.
  1017.  */
  1018. #define    TLB        30    /* Reassembly limit time */
  1019. #include <stdio.h>
  1020. #include "machdep.h"
  1021. #include "mbuf.h"
  1022. #include "timer.h"
  1023. #include "internet.h"
  1024. #include "ip.h"
  1025. #include "icmp.h"
  1026. #include "iface.h"
  1027.  
  1028. int ip_recv();    /* Should be void, but C complains */
  1029. char *calloc(),*malloc();
  1030.  
  1031. char ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  1032.  
  1033. struct reasm *reasmq;
  1034.  
  1035. #define    INSERT    0
  1036. #define    APPEND    1
  1037. #define    PREPEND    2
  1038.  
  1039. /* Send an IP datagram. Modeled after the example interface on p 32 of
  1040.  * RFC 791
  1041.  */
  1042. void
  1043. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  1044. int32 source;        /* source address */
  1045. int32 dest;        /* Destination address */
  1046. char protocol;        /* Protocol */
  1047. char tos;        /* Type of service */
  1048. char ttl;        /* Time-to-live */
  1049. struct mbuf *bp;    /* Data portion of datagram */
  1050. int16 length;        /* Optional length of data portion */
  1051. int16 id;        /* Optional identification */
  1052. char df;        /* Don't-fragment flag */
  1053. {
  1054.     struct mbuf *hbp;    /* mbuf containing IP header */
  1055.     struct ip_header *iph;    /* Pointer to IP header */
  1056.     static int16 id_cntr;    /* Datagram serial number */
  1057.     int16 hdr_len;        /* IP header length, bytes */
  1058.     void ip_route();    /* Datagram router */
  1059.  
  1060.     if(length == 0 && bp != NULLBUF)
  1061.         length = len_mbuf(bp);
  1062.     if(id == 0)
  1063.         id = id_cntr++;        
  1064.     if(ttl == 0)
  1065.         ttl = ip_ttl;
  1066.  
  1067.     /* Allocate an mbuf for the IP header */
  1068.     hdr_len = sizeof(struct ip_header);
  1069.     if((hbp = alloc_mbuf(hdr_len)) == NULLBUF){
  1070.         /* We really ought to source-quench the sender, but that would
  1071.          * probably fail too.
  1072.          */
  1073.         free_p(bp);
  1074.         return;
  1075.     }
  1076.     hbp->cnt = hdr_len;
  1077.  
  1078.     /* and fill it in */
  1079.     iph = (struct ip_header *)hbp->data;
  1080.  
  1081.     iph->v_ihl = (IPVERSION << 4) | (hdr_len/sizeof(int32));
  1082.     iph->tos = tos;
  1083.     iph->length = htons(hdr_len + length);
  1084.     iph->id = htons(id);
  1085.     if(df)
  1086.         iph->fl_offs = htons(DF);
  1087.     else
  1088.         iph->fl_offs = 0;
  1089.     iph->ttl = ttl;
  1090.     iph->protocol = protocol;
  1091.     iph->checksum = 0;
  1092.     iph->source = htonl(source);
  1093.     iph->dest = htonl(dest);
  1094.     iph->checksum = cksum(NULLHEADER,hbp,hdr_len);
  1095.     hbp->next = bp;
  1096.     ip_route(hbp,0);        /* Toss it to the router */
  1097. }
  1098.  
  1099. /* Reassemble incoming IP fragments and dispatch completed datagrams
  1100.  * to the proper transport module
  1101.  */
  1102. int    /* Should really be void */
  1103. ip_recv(bp,rxbroadcast)
  1104. struct mbuf *bp;
  1105. char rxbroadcast;
  1106. {
  1107.     register struct ip_header *ipp;    /* Pointer to original IP header */
  1108.     struct ip_header ip;    /* Extracted copy of header */
  1109.     int16 ip_len;        /* Length of IP header */
  1110.     struct mbuf *fraghandle();
  1111.     void (*recv)();    /* Function to call with completed datagram */
  1112.     void tcp_input(),udp_input(),icmp_input();
  1113.  
  1114.     ipp = (struct ip_header *)bp->data;
  1115.  
  1116.     /* Initial check for protocols we can't handle */
  1117.     switch(ipp->protocol & 0xff){
  1118.     case TCP_PTCL:
  1119.         recv = tcp_input;
  1120.         break;
  1121.     case UDP_PTCL:
  1122.         recv = udp_input;
  1123.         break;
  1124.     case ICMP_PTCL:
  1125.         recv = icmp_input;
  1126.         break;
  1127.     default:
  1128.         /* Send an ICMP Protocol Unknown response... */
  1129.         ip_stats.badproto++;
  1130.         /* ...unless it's a broadcast */
  1131.         if(!rxbroadcast)
  1132.             icmp_output(bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  1133.         free_p(bp);
  1134.         return;
  1135.     }
  1136.     ip_len = lonibble(ipp->v_ihl) * sizeof(int32);
  1137.     /* Extract IP header */
  1138.     pullup(&bp,(char *)&ip,ip_len);
  1139.  
  1140.     /* Convert to host byte order */
  1141.     ip.length = ntohs(ip.length) - ip_len;    /* Length of data portion */
  1142.     ip.id = ntohs(ip.id);
  1143.     ip.fl_offs = ntohs(ip.fl_offs);
  1144.     ip.source = ntohl(ip.source);
  1145.     ip.dest = ntohl(ip.dest);
  1146.  
  1147.     /* If we have a complete packet, call the next layer
  1148.      * to handle the result
  1149.      */
  1150.     if((bp = fraghandle(&ip,bp)) != NULLBUF)
  1151.         (*recv)(bp,ip.protocol,ip.source,ip.dest,ip.tos,ip.length,rxbroadcast);
  1152. }
  1153. /* Process IP datagram fragments
  1154.  * If datagram is complete, return it with ip->length containing its
  1155.  * entire length; otherwise return NULLBUF
  1156.  */
  1157. static
  1158. struct mbuf *
  1159. fraghandle(ip,bp)
  1160. struct ip_header *ip;    /* IP header, host byte order */
  1161. struct mbuf *bp;    /* The fragment itself */
  1162. {
  1163.     void ip_timeout(),freefrag(),free_reasm();
  1164.     struct reasm *lookup_reasm(),*creat_reasm();
  1165.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  1166.     struct frag *lastfrag,*nextfrag,*tfp,*newfrag();
  1167.     struct mbuf *tbp;
  1168.     int16 i;
  1169.     int16 offset;        /* Index of first byte in fragment */
  1170.     int16 last;        /* Index of first byte beyond fragment */
  1171.     char mf;        /* 1 if not last fragment, 0 otherwise */
  1172.  
  1173.     offset = (ip->fl_offs & F_OFFSET) << 3;    /* Convert to bytes */
  1174.     last = offset + ip->length;
  1175.     mf = (ip->fl_offs & MF) ? 1 : 0;
  1176.  
  1177.     rp = lookup_reasm(ip);
  1178.     if(offset == 0 && !mf){
  1179.         /* Complete datagram received. Discard any earlier fragments */
  1180.         if(rp != NULLREASM)
  1181.             free_reasm(rp);
  1182.  
  1183.         return bp;
  1184.     }
  1185.     if(rp == NULLREASM){
  1186.         /* First fragment; create new reassembly descriptor */
  1187.         if((rp = creat_reasm(ip)) == NULLREASM){
  1188.             /* No space for descriptor, drop fragment */
  1189.             free_p(bp);
  1190.             return NULLBUF;
  1191.         }
  1192.     }
  1193.     /* Keep restarting timer as long as we keep getting fragments */
  1194.     stop_timer(&rp->timer);
  1195.     start_timer(&rp->timer);
  1196.  
  1197.     /* If this is the last fragment, we now know how long the
  1198.      * entire datagram is; record it
  1199.      */
  1200.     if(!mf)
  1201.         rp->length = last;
  1202.  
  1203.     /* Set nextfrag to the first fragment which begins after us,
  1204.      * and lastfrag to the last fragment which begins before us
  1205.      */
  1206.     lastfrag = NULLFRAG;
  1207.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  1208.         if(nextfrag->offset > offset)
  1209.             break;
  1210.         lastfrag = nextfrag;
  1211.     }
  1212.     /* Check for overlap with preceeding fragment */
  1213.     if(lastfrag != NULLFRAG  && offset < lastfrag->last){
  1214.         /* Strip overlap from new fragment */
  1215.         i = lastfrag->last - offset;
  1216.         pullup(&bp,NULLCHAR,i);
  1217.         if(bp == NULLBUF)
  1218.             return NULLBUF;    /* Nothing left */
  1219.         offset += i;
  1220.     }
  1221.     /* Look for overlap with succeeding segments */
  1222.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  1223.         tfp = nextfrag->next;    /* save in case we delete fp */
  1224.  
  1225.         if(nextfrag->offset >= last)
  1226.             break;    /* Past our end */
  1227.         /* Trim the front of this entry; if nothing is
  1228.          * left, remove it.
  1229.          */
  1230.         i = last - nextfrag->offset;
  1231.         pullup(&nextfrag->buf,NULLCHAR,i);
  1232.         if(nextfrag->buf == NULLBUF){
  1233.             /* superseded; delete from list */
  1234.             if(nextfrag->prev != NULLFRAG)
  1235.                 nextfrag->prev->next = nextfrag->next;
  1236.             else
  1237.                 rp->fraglist = nextfrag->next;
  1238.             if(tfp->next != NULLFRAG)
  1239.                 nextfrag->next->prev = nextfrag->prev;
  1240.             freefrag(nextfrag);
  1241.         } else
  1242.             nextfrag->offset = last;
  1243.     }
  1244.     /* Lastfrag now points, as before, to the fragment before us;
  1245.      * nextfrag points at the next fragment. Check to see if we can
  1246.      * join to either or both fragments.
  1247.      */
  1248.     i = INSERT;
  1249.     if(lastfrag != NULLFRAG && lastfrag->last == offset)
  1250.         i |= APPEND;
  1251.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  1252.         i |= PREPEND;
  1253.     switch(i){
  1254.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  1255.         tfp = newfrag(offset,last,bp);
  1256.         tfp->prev = lastfrag;
  1257.         tfp->next = nextfrag;
  1258.         if(lastfrag != NULLFRAG)
  1259.             lastfrag->next = tfp;    /* Middle of list */
  1260.         else
  1261.             rp->fraglist = tfp;    /* First on list */
  1262.         if(nextfrag != NULLFRAG)
  1263.             nextfrag->prev = tfp;
  1264.         break;
  1265.     case APPEND:    /* Append to lastfrag */
  1266.         append(&lastfrag->buf,bp);
  1267.         lastfrag->last = last;    /* Extend forward */
  1268.         break;
  1269.     case PREPEND:    /* Prepend to nextfrag */
  1270.         tbp = nextfrag->buf;
  1271.         nextfrag->buf = bp;
  1272.         append(&nextfrag->buf,tbp);
  1273.         nextfrag->offset = offset;    /* Extend backward */
  1274.         break;
  1275.     case (APPEND|PREPEND):
  1276.         /* Consolidate by appending this fragment and nextfrag
  1277.          * to lastfrag and removing the nextfrag descriptor
  1278.          */
  1279.         append(&lastfrag->buf,bp);
  1280.         append(&lastfrag->buf,nextfrag->buf);
  1281.         nextfrag->buf = NULLBUF;
  1282.         lastfrag->last = nextfrag->last;
  1283.  
  1284.         /* Finally unlink and delete the now unneeded nextfrag */
  1285.         lastfrag->next = nextfrag->next;
  1286.         if(nextfrag->next != NULLFRAG)
  1287.             nextfrag->next->prev = lastfrag;
  1288.         freefrag(nextfrag);
  1289.         break;
  1290.     }
  1291.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  1292.         && rp->length != 0){
  1293.         /* We've gotten a complete datagram, so extract it from the
  1294.          * reassembly buffer and pass it on.
  1295.          */
  1296.         bp = rp->fraglist->buf;
  1297.         rp->fraglist->buf = NULLBUF;
  1298.         ip->length = rp->length;    /* Tell IP the entire length */
  1299.         free_reasm(rp);
  1300.         return bp;
  1301.     } else
  1302.         return NULLBUF;
  1303. }
  1304. static struct reasm *
  1305. lookup_reasm(ip)
  1306. struct ip_header *ip;
  1307. {
  1308.     register struct reasm *rp;
  1309.  
  1310.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  1311.         if(ip->source == rp->source && ip->dest == rp->dest
  1312.          && ip->protocol == rp->protocol && ip->id == rp->id)
  1313.             return rp;
  1314.     }
  1315.     return NULLREASM;
  1316. }
  1317. #ifdef    FOO
  1318. static
  1319. int16
  1320. hash_reasm(source,dest,protocol,id)
  1321. int32 source;
  1322. int32 dest,
  1323. char protocol;
  1324. int16 id;
  1325. {
  1326.     register int16 hval;
  1327.  
  1328.     hval = loword(source);
  1329.     hval ^= hiword(source);
  1330.     hval ^= loword(dest);
  1331.     hval ^= hiword(dest);
  1332.     hval ^= protocol & 0xff;
  1333.     hval ^= id;
  1334.     hval %= RHASH;
  1335.     return hval;
  1336. }
  1337. #endif
  1338. /* Create a reassembly descriptor,
  1339.  * put at head of reassembly list
  1340.  */
  1341. static struct reasm *
  1342. creat_reasm(ip)
  1343. register struct ip_header *ip;
  1344. {
  1345.     register struct reasm *rp;
  1346.  
  1347.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  1348.         return rp;    /* No space for descriptor */
  1349.     rp->source = ip->source;
  1350.     rp->dest = ip->dest;
  1351.     rp->id = ip->id;
  1352.     rp->protocol = ip->protocol;
  1353.     rp->timer.start = TLB;
  1354.     rp->timer.func = ip_timeout;
  1355.     rp->timer.arg = (int *)rp;
  1356.  
  1357.     rp->next = reasmq;
  1358.     if(rp->next != NULLREASM)
  1359.         rp->next->prev = rp;
  1360.     reasmq = rp;
  1361.     return rp;
  1362. }
  1363.  
  1364. /* Free all resources associated with a reassembly descriptor */
  1365. static void
  1366. free_reasm(rp)
  1367. register struct reasm *rp;
  1368. {
  1369.     register struct frag *fp;
  1370.  
  1371.     stop_timer(&rp->timer);
  1372.     /* Remove from list of reassembly descriptors */
  1373.     if(rp->prev != NULLREASM)
  1374.         rp->prev->next = rp->next;
  1375.     else
  1376.         reasmq = rp->next;
  1377.     if(rp->next != NULLREASM)
  1378.         rp->next->prev = rp->prev;
  1379.     /* Free any fragments on list, starting at beginning */
  1380.     while((fp = rp->fraglist) != NULLFRAG){
  1381.         rp->fraglist = fp->next;
  1382.         free_p(fp->buf);
  1383.         free((char *)fp);
  1384.     }
  1385.     free((char *)rp);
  1386. }
  1387.  
  1388. /* Handle reassembly timeouts by deleting all reassembly resources */
  1389. static void
  1390. ip_timeout(arg)
  1391. int *arg;
  1392. {
  1393.     register struct reasm *rp;
  1394.  
  1395.     rp = (struct reasm *)arg;
  1396.     free_reasm(rp);
  1397. }
  1398. /* Create a fragment */
  1399. static
  1400. struct frag *
  1401. newfrag(offset,last,bp)
  1402. int16 offset,last;
  1403. struct mbuf *bp;
  1404. {
  1405.     struct frag *fp;
  1406.  
  1407.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  1408.         /* Drop fragment */
  1409.         free_p(bp);
  1410.         return NULLFRAG;
  1411.     }
  1412.     fp->buf = bp;
  1413.     fp->offset = offset;
  1414.     fp->last = last;
  1415.     return fp;
  1416. }
  1417. /* Delete a fragment, return next one on queue */
  1418. static
  1419. void
  1420. freefrag(fp)
  1421. struct frag *fp;
  1422. {
  1423.     free_p(fp->buf);
  1424.     free((char *)fp);
  1425. }
  1426. #ifdef TRACE
  1427. int
  1428. doipstat(argc,argv)
  1429. int argc;
  1430. char *argv[];
  1431. {
  1432.     extern struct ip_stats ip_stats;
  1433.     extern struct reasm *reasmq;
  1434.     register struct reasm *rp;
  1435.     register struct frag *fp;
  1436.     char *inet_ntoa();
  1437.  
  1438.     printf("total %ld runt %u len err %u vers err %u",
  1439.         ip_stats.total,ip_stats.runt,ip_stats.length,ip_stats.version);
  1440.     printf(" chksum err %u badproto %u\r\n",
  1441.         ip_stats.checksum,ip_stats.badproto);
  1442.  
  1443.     if(reasmq != NULLREASM)
  1444.         printf("Reassembly fragments:\r\n");
  1445.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  1446.         printf("src %s",inet_ntoa(rp->source));
  1447.         printf(" dest %s",inet_ntoa(rp->dest));
  1448.         printf(" id %u pctl %u time %u len %u\r\n",
  1449.             rp->id,rp->protocol,rp->timer.count,rp->length);
  1450.         for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  1451.             printf(" offset %u last %u\r\n",fp->offset,fp->last);
  1452.         }
  1453.     }
  1454.     return 0;
  1455. }
  1456. #endif
  1457. SHAR_EOF
  1458. cat << \SHAR_EOF > udp.c
  1459. /* Send and receive User Datagram Protocol packets */
  1460. #include "machdep.h"
  1461. #include "mbuf.h"
  1462. #include "netuser.h"
  1463. #include "udp.h"
  1464. #include "internet.h"
  1465.  
  1466. struct udp_cb *udps[NUDP];    /* Hash table for UDP structures */
  1467. struct udp_stat udp_stat;    /* Statistics */
  1468.  
  1469. /* Create a UDP control block for lsocket, so that we can queue
  1470.  * incoming datagrams.
  1471.  */
  1472. int
  1473. open_udp(lsocket,r_upcall)
  1474. struct socket *lsocket;
  1475. void (*r_upcall)();
  1476. {
  1477.     char *malloc();
  1478.     register struct udp_cb *up;
  1479.     struct udp_cb *lookup_udp();
  1480.     int16 hval,hash_udp();
  1481.  
  1482.     if((up = lookup_udp(lsocket)) != NULLUDP)
  1483.         return 0;    /* Already exists */
  1484.     if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
  1485.         net_error = NO_SPACE;
  1486.         return -1;
  1487.     }
  1488.     up->rcvq = NULLBUF;
  1489.     up->rcvcnt = 0;
  1490.     up->socket.address = lsocket->address;
  1491.     up->socket.port = lsocket->port;
  1492.     up->r_upcall = r_upcall;
  1493.  
  1494.     hval = hash_udp(lsocket);
  1495.     up->next = udps[hval];
  1496.     up->prev = NULLUDP;
  1497.     up->next->prev = up;
  1498.     udps[hval] = up;
  1499.     return 0;
  1500. }
  1501.  
  1502. /* Send a UDP datagram */
  1503. int
  1504. send_udp(lsocket,fsocket,tos,ttl,bp,length,id,df)
  1505. struct socket *lsocket;        /* Source socket */
  1506. struct socket *fsocket;        /* Destination socket */
  1507. char tos;                    /* Type-of-service for IP */
  1508. char ttl;                    /* Time-to-live for IP */
  1509. struct mbuf *bp;            /* Data field, if any */
  1510. int16 length;                /* Length of data field */
  1511. int16 id;                    /* Optional ID field for IP */
  1512. char df;                    /* Don't Fragment flag for IP */
  1513. {
  1514.     struct mbuf *hbp;
  1515.     int16 hdr_len;
  1516.     struct pseudo_header ph;
  1517.     struct udp_header *uhdr;
  1518.  
  1519.     if(length == 0 && bp != NULLBUF)
  1520.         length = len_mbuf(bp);
  1521.     hdr_len = sizeof(struct udp_header);
  1522.     length += hdr_len;
  1523.  
  1524.     /* Allocate UDP protocol header and fill it in */
  1525.     if((hbp = alloc_mbuf(hdr_len)) == NULLBUF){
  1526.         net_error = NO_SPACE;
  1527.         return -1;
  1528.     }
  1529.     hbp->cnt = hdr_len;
  1530.  
  1531.     uhdr = (struct udp_header *)hbp->data;
  1532.     uhdr->source = htons(lsocket->port);
  1533.     uhdr->dest = htons(fsocket->port);
  1534.     uhdr->length = htons(length);
  1535.     uhdr->checksum = 0;
  1536.  
  1537.     /* Link in the user data */
  1538.     hbp->next = bp;
  1539.  
  1540.     /* Create IP pseudo-header, compute checksum and send it */
  1541.     ph.length = length;
  1542.     ph.source = lsocket->address;
  1543.     ph.dest = fsocket->address;
  1544.     ph.protocol = UDP_PTCL;
  1545.     ph.zero = 0;
  1546.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  1547.      * the spec requires us to change zeros into ones to distinguish an
  1548.       * all-zero checksum from no checksum at all
  1549.      */
  1550.     if((uhdr->checksum = cksum(&ph,hbp,length)) == 0)
  1551.         uhdr->checksum = 0xffffffff;
  1552.  
  1553.     udp_stat.sent++;
  1554.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,hbp,length,id,df);
  1555.     return length;
  1556. }
  1557.  
  1558. /* Accept a waiting datagram, if available. Returns length of datagram */
  1559. int
  1560. recv_udp(lsocket,fsocket,bp)
  1561. struct socket *lsocket;        /* Local socket to receive on */
  1562. struct socket *fsocket;        /* Place to stash incoming socket */
  1563. struct mbuf **bp;            /* Place to stash data packet */
  1564. {
  1565.     struct udp_cb *lookup_udp();
  1566.     register struct udp_cb *up;
  1567.     struct socket *sp;
  1568.     struct mbuf *buf;
  1569.     int16 length;
  1570.  
  1571.     up = lookup_udp(lsocket);
  1572.     if(up == NULLUDP){
  1573.         net_error = NO_CONN;
  1574.         return -1;
  1575.     }
  1576.     if(up->rcvcnt == 0){
  1577.         net_error = WOULDBLK;
  1578.         return -1;
  1579.     }
  1580.     buf = dequeue(&up->rcvq);
  1581.     up->rcvcnt--;
  1582.  
  1583.     sp = (struct socket *)buf->data;
  1584.     /* Fill in the user's foreign socket structure, if given */
  1585.     if(fsocket != NULLSOCK){
  1586.         fsocket->address = sp->address;
  1587.         fsocket->port = sp->port;
  1588.     }
  1589.     /* Strip socket header and hand data to user */
  1590.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  1591.     length = len_mbuf(buf);
  1592.     if(bp != (struct mbuf **)NULL)
  1593.         *bp = buf;
  1594.     else
  1595.         free_p(buf);
  1596.     return length;
  1597. }
  1598. /* Delete a UDP control block */
  1599. int
  1600. del_udp(lsocket)
  1601. struct socket *lsocket;
  1602. {
  1603.     register struct udp_cb *up;
  1604.     struct udp_cb *lookup_udp();
  1605.     struct mbuf *bp;
  1606.     int16 hval;
  1607.  
  1608.     if((up = lookup_udp(lsocket)) == NULLUDP){
  1609.         net_error = INVALID;
  1610.         return -1;
  1611.     }        
  1612.     /* Get rid of any pending packets */
  1613.     while(up->rcvcnt != 0){
  1614.         bp = up->rcvq;
  1615.         up->rcvq = up->rcvq->anext;
  1616.         free_p(bp);
  1617.         up->rcvcnt--;
  1618.     }
  1619.     hval = hash_udp(&up->socket);
  1620.     if(udps[hval] == up){
  1621.         /* First on list */
  1622.         udps[hval] = up->next;
  1623.         up->next->prev = NULLUDP;
  1624.     } else {
  1625.         up->prev->next = up->next;
  1626.         up->next->prev = up->prev;
  1627.     }
  1628.     free((char *)up);
  1629.     return 0;
  1630. }
  1631. /* Process an incoming UDP datagram */
  1632. void
  1633. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  1634. struct mbuf *bp;
  1635. char protocol;
  1636. int32 source;        /* Source IP address */
  1637. int32 dest;        /* Dest IP address */
  1638. char tos;
  1639. int16 length;
  1640. char rxbroadcast;    /* The only protocol that accepts 'em */
  1641. {
  1642.     struct pseudo_header ph;
  1643.     struct udp_header udp;
  1644.     struct udp_cb *up,*lookup_udp();
  1645.     struct socket lsocket;
  1646.     struct socket *fsocket;
  1647.     struct mbuf *sp;
  1648.     int ckfail = 0;
  1649.  
  1650.     if(bp == NULLBUF)
  1651.         return;
  1652.  
  1653.     udp_stat.rcvd++;
  1654.  
  1655.     /* Create pseudo-header and verify checksum */
  1656.     ph.source = source;
  1657.     ph.dest = dest;
  1658.     ph.protocol = protocol;
  1659.     ph.length = length;
  1660.     ph.zero = 0;
  1661.     if(cksum(&ph,bp,length) != 0)
  1662.         /* Checksum apparently failed, note for later */
  1663.         ckfail++;
  1664.  
  1665.     /* Extract UDP header in host order */
  1666.     pullup(&bp,(char *)&udp,sizeof(struct udp_header));
  1667.  
  1668.     /* If the checksum field is zero, then ignore a checksum error.
  1669.      * I think this is dangerously wrong, but it is in the spec.
  1670.      */
  1671.     if(ckfail && udp.checksum != 0){
  1672.         udp_stat.cksum++;
  1673.         free_p(bp);
  1674.         return;
  1675.     }
  1676.     udp.dest = ntohs(udp.dest);
  1677.     udp.source = ntohs(udp.source);
  1678.  
  1679.     /* If this was a broadcast packet, pretend it was sent to us */
  1680.     if(rxbroadcast){
  1681.         lsocket.address = ip_addr;
  1682.         udp_stat.bdcsts++;
  1683.     } else
  1684.         lsocket.address = dest;
  1685.  
  1686.     lsocket.port = udp.dest;
  1687.     /* See if there's somebody around to read it */
  1688.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  1689.         /* Nope, toss it on the floor */
  1690.         udp_stat.unknown++;
  1691.         free_p(bp);
  1692.         return;
  1693.     }
  1694.     /* Create a buffer which will contain the foreign socket info */
  1695.     if((sp = alloc_mbuf(sizeof(struct socket))) == NULLBUF){
  1696.         /* No space, drop whole packet */
  1697.         free_p(bp);
  1698.         return;
  1699.     }
  1700.     sp->cnt = sizeof(struct socket);
  1701.  
  1702.     fsocket = (struct socket *)sp->data;
  1703.     fsocket->address = source;
  1704.     fsocket->port = udp.source;
  1705.  
  1706.     /* Yes, remove the now redundant UDP header, chain the foreign socket
  1707.      * info in front of it and queue it
  1708.      */
  1709.  
  1710.     sp->next = bp;
  1711.     enqueue(&up->rcvq,sp);
  1712.     up->rcvcnt++;
  1713.     if(up->r_upcall)
  1714.         (*up->r_upcall)(&lsocket,up->rcvcnt);
  1715. }
  1716. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  1717. static
  1718. struct udp_cb *
  1719. lookup_udp(socket)
  1720. struct socket *socket;
  1721. {
  1722.     register struct udp_cb *up;
  1723.     int16 hash_udp();
  1724.  
  1725.     up = udps[hash_udp(socket)];
  1726.     while(up != NULLUDP){
  1727.         if(bcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  1728.             break;
  1729.         up = up->next;
  1730.     }
  1731.     return up;
  1732. }
  1733.  
  1734. /* Hash a UDP socket (address and port) structure */
  1735. static
  1736. int16
  1737. hash_udp(socket)
  1738. struct socket *socket;
  1739. {
  1740.     int16 hval;
  1741.  
  1742.     /* Compute hash function on socket structure */
  1743.     hval = hiword(socket->address);
  1744.     hval ^= loword(socket->address);
  1745.     hval ^= socket->port;
  1746.     hval %= NUDP;
  1747.     return hval;
  1748. }
  1749. #ifdef    TRACE
  1750. /* Dump UDP statistics and control blocks */
  1751. doudpstat()
  1752. {
  1753.     extern struct udp_stat udp_stat;
  1754.     char *psocket();
  1755.     register struct udp_cb *udp;
  1756.     register int i;
  1757.  
  1758.     printf("sent %u rcvd %u bdcsts %u cksum err %u unknown socket %u\r\n",
  1759.     udp_stat.sent,udp_stat.rcvd,udp_stat.bdcsts,udp_stat.cksum,udp_stat.unknown);
  1760. #ifdef    AMIGA
  1761.     printf("&UCB   Rcv-Q  Local socket\r\n");
  1762. #else
  1763.     printf("&UCB Rcv-Q  Local socket\r\n");
  1764. #endif
  1765.     for(i=0;i<NUDP;i++){
  1766.         for(udp = udps[i];udp != NULLUDP; udp = udp->next){
  1767. #ifdef    AMIGA
  1768.             printf("%6lx%6u  %s\r\n",(unsigned long)udp,udp->rcvcnt,
  1769. #else
  1770.             printf("%x%6u  %s\r\n",(int)udp,udp->rcvcnt,
  1771. #endif
  1772.              psocket(&udp->socket));
  1773.         }
  1774.     }
  1775. }
  1776. /* Dump a UDP header */
  1777. void
  1778. udp_dump(bp,source,dest,check)
  1779. struct mbuf *bp;
  1780. int32 source,dest;
  1781. int check;        /* If 0, bypass checksum verify */
  1782. {
  1783.     register struct udp_header *udph;
  1784.     struct pseudo_header ph;
  1785.     int i;
  1786.     char tmpbuf;
  1787.  
  1788.     if(bp == NULLBUF)
  1789.         return;
  1790.     /* If packet isn't in a single buffer, make a temporary copy and
  1791.      * note the fact so we free it later
  1792.      */
  1793.     if(bp->next != NULLBUF){
  1794.         bp = copy_p(bp,len_mbuf(bp));
  1795.         tmpbuf = 1;
  1796.     } else
  1797.         tmpbuf = 0;
  1798.  
  1799.     udph = (struct udp_header *)bp->data;
  1800.     printf("UDP:");
  1801.     printf(" %u->%u",ntohs(udph->source),
  1802.         ntohs(udph->dest));
  1803.     printf(" len %u",ntohs(udph->length));
  1804.     
  1805.     if(check){
  1806.         /* Verify checksum */
  1807.         ph.source = source;
  1808.         ph.dest = dest;
  1809.         ph.zero = 0;
  1810.         ph.protocol = UDP_PTCL;
  1811.         ph.length = len_mbuf(bp);
  1812.         if(udph->checksum != 0 && (i = cksum(&ph,bp,ph.length)) != 0)
  1813.             printf(" CHECKSUM ERROR (%u)",i);
  1814.     }
  1815.     printf("\r\n");
  1816.     if(tmpbuf)
  1817.         free_p(bp);
  1818. }
  1819.  
  1820. #endif
  1821. SHAR_EOF
  1822. #    End of shell archive
  1823. exit 0
  1824. -- 
  1825. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1826. Have five nice days.
  1827.